import cv2
import mediapipe as mp
#Mediapipe是google的一个开源项目，
# 可以提供开源的、跨平台的常用ML(machine learning)方案.Mediapipe实际上是一个集成的机器学习视觉算法的工具库，
# 包含了人脸检测、人脸关键点、手势识别、头像分割和姿态识别等各种模型。
# Mediapipe具备的优点有：
# 1）支持各种平台和语言，包括IOS，Android，C++，Python，JAVAScript，Coral等；
# 2）速度快，各种模型基本上可以做到实时运行。
# Mediapipe在实际应用中的例子：1）人脸检测；
# 2）FaceMesh：从图像/视频中重建出人脸的3D Mesh，可以用于AR渲染；
# 3）人像分割：从图像/视频中把人分割出来，可用于视频会议如Zoom、钉钉；
# 4）手势识别和跟踪：可以识别标出手部21个关键点的3D坐标；
# 5）人体姿态识别：可以识别标出人体33个关键点的3D坐标。

#安装Mediapipe
#1)安装OpenCV,终端执行pip install opencv-contrib-python
#2)安装Mediapipe，终端执行pip install mediapipe，或者使用国内镜像 pip install mediapipe -i https://pypi.tuna.tsinghua.edu.cn/simple/
 
class HandDetector:
 
    def __init__(self):
        # 先定义results和handsjh两个成员变量，先将其定义为空
        self.results = None
        self.handsjh = None
        # 为mp.solutions.hands.Hands()命名为hands，使后续代码比较简短
        self.hands = mp.solutions.hands.Hands()
 
    def find_hands(self, img, draw=True):
        # 将img图像由BGR转换成RGB
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # 处理手部检测和追踪的数据，并返回一个mp.solutions.hands.Hands()对象，其中包含了检测到的手部数据
        self.results = self.hands.process(imgRGB)
        if draw:
            # 确定是否有多只手的检测结果
            if self.results.multi_hand_landmarks:
                # 遍历multi_hand_landmarks中的数据
                for handlms in self.results.multi_hand_landmarks:
                    #画出21个手势地标并其连起来
                    mp.solutions.drawing_utils.draw_landmarks(img, handlms, mp.solutions.hands.HAND_CONNECTIONS)
        return img
 
    def find_positions(self, img, hand_no=0):
        # 先将handsjh定义为空列表
        self.handsjh = []
        if self.results.multi_hand_landmarks:
            # 选择索引值为hand_no的手部地标数据，并将其赋值给变量hand
            hand = self.results.multi_hand_landmarks[hand_no]
            # 使用enumerate()函数对该手的每一个地标进行遍历，并将地标的索引值赋值给id，，并将每个地标的x、y值赋值给lm
            for id, lm in enumerate(hand.landmark):
                # 计算图像img的长和宽
                h, w, c = img.shape
                # 计算每个地标在img图像对应位置的x、y坐标
                cx, cy = int(lm.x * w), int(lm.y * h)
                # 将计算到的数据存放到handsjh列表中
                self.handsjh.append([id, cx, cy])
        return self.handsjh
   